package wrapper

import (
	"gitee.com/ymofen/gobase"
	"os"
	"strings"
	"time"

	"github.com/suiyunonghen/dxsvalue"
)

func dxvalueToDateTime(v *dxsvalue.DxValue, def time.Time) time.Time {
	if v.DataType == dxsvalue.VT_String || v.DataType == dxsvalue.VT_RawString {
		return gobase.TryStrToTime(v.String(), def.Location(), def)
	} else if v.DataType == dxsvalue.VT_DateTime {
		return v.DateTime().ToTime()
	}
	return def
}

func dxvalueAsJsonBytes(this *dxsvalue.DxValue, escape bool, format bool) []byte {
	if this == nil {
		return nil
	}
	// sty := dxsvalue.JSE_NoEscape  // 有BUG,如果存在转义的时候 json.SetKeyString("param", "a\\\"b")
	sty := dxsvalue.JSE_OnlyAnsiChar
	if escape {
		sty = dxsvalue.JSE_AllEscape
	}

	if format {
		return dxsvalue.Value2FormatJson(this, sty, true, nil)
	} else {
		return dxsvalue.Value2Json(this, sty, true, nil)
	}
}

func CloneFrom(src *SuperValue) *SuperValue {
	if src == nil {
		return nil
	}
	return src.Clone()
}

func CloneFromCache(src *SuperValue, useCache bool) *SuperValue {
	if src == nil {
		return nil
	}
	return src.CloneCache(useCache)
}

func AsJson(json *SuperValue, escap bool, format bool) string {
	if json == nil {
		return ""
	} else {
		return json.AsJSONStringEx(escap, format)
	}
}

func dxvalueToStr(v *dxsvalue.DxValue, def string) string {
	if v == nil {
		return def
	}
	vtype := v.DataType
	if vtype == dxsvalue.VT_Object || vtype == dxsvalue.VT_Array {
		return string(dxvalueAsJsonBytes(v, false, true))
	} else {
		return v.StringDef(def)
	}
}

func dxvalueToVar(v *dxsvalue.DxValue) interface{} {
	if v == nil {
		return nil
	}
	vtype := v.DataType
	if vtype == dxsvalue.VT_Int {
		v1 := v.Int()
		return v1
	} else if vtype == dxsvalue.VT_Double || vtype == dxsvalue.VT_Float {
		v1 := v.Double()
		return v1
	} else if vtype == dxsvalue.VT_DateTime {
		v1 := v.DateTime().ToTime()
		return v1
	} else if vtype == dxsvalue.VT_Binary {
		return v.Binary()
	} else if vtype == dxsvalue.VT_False {
		return false
	} else if vtype == dxsvalue.VT_True {
		return true
	} else if vtype == dxsvalue.VT_NULL {
		return nil
	} else if vtype == dxsvalue.VT_Object || vtype == dxsvalue.VT_Array {
		return string(dxsvalue.Value2Json(v, dxsvalue.JSE_OnlyAnsiChar, false, nil))
	} else {
		v1 := v.String()
		return v1
	}
}

func GetValueByName(v *SuperValue, name string) *SuperValue {
	if v == nil {
		return nil
	}
	return v.ValueByName(name)
}

func valIsString(v *dxsvalue.DxValue) bool {
	if v == nil {
		return false
	}
	if v.DataType == dxsvalue.VT_String || v.DataType == dxsvalue.VT_RawString {
		return true
	}
	return false
}

func valAsDateTime(v *dxsvalue.DxValue, def time.Time) time.Time {
	if v == nil {
		return def
	}
	switch v.DataType {
	case dxsvalue.VT_Int:
		return gobase.LocationCopy(time.Unix(v.Int(), 0), def)
	case dxsvalue.VT_String, dxsvalue.VT_RawString:
		return gobase.TryStrToTime(v.String(), def.Location(), def)
	}
	return v.DateTime().ToTime()
}

func Value2File(v *dxsvalue.DxValue, fileName string, BOMFile, escapestr bool, format bool) error {

	if file, err := os.OpenFile(fileName, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0666); err == nil {
		defer file.Close()
		if BOMFile {
			file.Write([]byte{0xEF, 0xBB, 0xBF})
		}
		style := dxsvalue.JSE_OnlyAnsiChar
		if escapestr {
			style = dxsvalue.JSE_AllEscape
		}
		var dst []byte
		if format {
			dst = dxsvalue.Value2FormatJson(v, style, true, nil)
		} else {
			dst = dxsvalue.Value2Json(v, style, true, nil)
		}
		_, err := file.Write(dst)
		return err
	} else {
		return err
	}
}

/*
*

	0: equal
	-1 if v1 < v2, and +1 if v1 > v2
*/
func Compare(v1, v2 *SuperValue) int {
	if v1 == nil && v2 == nil {
		return 0
	}
	if v1 == nil {
		return -1
	}

	if v2 == nil {
		return 1
	}

	str1 := v1.String()
	str2 := v2.String()
	return strings.Compare(str1, str2)
}

func CompareLess(v1 *SuperValue, v2 *SuperValue, k1 string, k2 string) bool {
	var s1, s2 *dxsvalue.DxValue
	if v1.val != nil {
		s1 = v1.val.Find(k1)
	}
	if v2.val != nil {
		s2 = v2.val.Find(k2)
	}
	if s1 == nil {
		return false
	}

	if s2 == nil {
		return true
	}

	if s1.DataType == dxsvalue.VT_String || s1.DataType == dxsvalue.VT_RawString {
		// 尝试使用日期
		str1 := s1.String()
		str2 := s2.String()
		t1 := gobase.TryStrToTimeDefZero(str1, time.Local)
		if !gobase.TimeIsUnixZero(t1) {
			t2 := gobase.TryStrToTimeDefZero(str2, time.Local)
			return t1.Before(t2)
		}
		return str1 <= str2
	}

	if s1.DataType == dxsvalue.VT_Int || s1.DataType == dxsvalue.VT_False || s1.DataType == dxsvalue.VT_True {
		return s1.Int() < s2.Int()
	}

	if s1.DataType == dxsvalue.VT_Double || s1.DataType == dxsvalue.VT_Float {
		return s1.Double() < s2.Double()
	}

	if s1.DataType == dxsvalue.VT_DateTime {
		return s1.DateTime().ToTime().Before(s2.DateTime().ToTime())
	}

	return true

}

/*
**
 */
func dxvalueEqV(v *dxsvalue.DxValue, v1 interface{}) bool {
	if v == nil {
		if v1 == nil {
			return true
		} else {
			return false
		}
	}
	if v1 == nil {
		if v == nil {
			return true
		} else {
			return false
		}
	}

	switch s := v1.(type) {
	case time.Time:
		loc := gobase.ZeroTime
		loc.Local()
		return dxvalueToDateTime(v, loc) == s
	case string:
		return v.String() == s
	case int:
		return v.Int() == int64(s)
	case int8:
		return v.Int() == int64(s)
	case int16:
		return v.Int() == int64(s)
	case int32:
		return v.Int() == int64(s)
	case int64:
		return v.Int() == int64(s)
	case uint:
		return v.Int() == int64(s)
	case uint8:
		return v.Int() == int64(s)
	case uint16:
		return v.Int() == int64(s)
	case uint32:
		return v.Int() == int64(s)
	case uint64:
		return v.Int() == int64(s)
	case float32:
		return v.Float() == s
	case float64:
		return v.Double() == s
	case bool:
		return v.Bool() == s
	case *SuperValue:
		return v.String() == s.val.String()
	case nil:
		return v == nil
	default:
		return v.String() == s
	}
	return false

}
